package com.atguigu.tingshu.order.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.date.CalendarUtil;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.lang.Assert;
import cn.hutool.core.util.IdUtil;
import com.alibaba.nacos.common.utils.CollectionUtils;
import com.alibaba.nacos.common.utils.UuidUtils;
import com.atguigu.tingshu.account.AccountFeignClient;
import com.atguigu.tingshu.album.AlbumFeignClient;
import com.atguigu.tingshu.common.constant.RedisConstant;
import com.atguigu.tingshu.common.constant.SystemConstant;
import com.atguigu.tingshu.common.delay.DelayMsgService;
import com.atguigu.tingshu.common.execption.GuiguException;
import com.atguigu.tingshu.common.result.Result;
import com.atguigu.tingshu.common.util.AuthContextHolder;
import com.atguigu.tingshu.model.album.AlbumInfo;
import com.atguigu.tingshu.model.album.TrackInfo;
import com.atguigu.tingshu.model.order.OrderDerate;
import com.atguigu.tingshu.model.order.OrderDetail;
import com.atguigu.tingshu.model.order.OrderInfo;
import com.atguigu.tingshu.model.user.VipServiceConfig;
import com.atguigu.tingshu.order.helper.SignHelper;
import com.atguigu.tingshu.order.mapper.OrderDerateMapper;
import com.atguigu.tingshu.order.mapper.OrderDetailMapper;
import com.atguigu.tingshu.order.mapper.OrderInfoMapper;
import com.atguigu.tingshu.order.service.OrderInfoService;
import com.atguigu.tingshu.user.client.UserFeignClient;
import com.atguigu.tingshu.vo.account.AccountLockVo;
import com.atguigu.tingshu.vo.album.AlbumStatVo;
import com.atguigu.tingshu.vo.order.OrderDerateVo;
import com.atguigu.tingshu.vo.order.OrderDetailVo;
import com.atguigu.tingshu.vo.order.OrderInfoVo;
import com.atguigu.tingshu.vo.order.TradeVo;
import com.atguigu.tingshu.vo.user.UserInfoVo;
import com.atguigu.tingshu.vo.user.UserPaidRecordVo;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import io.seata.spring.annotation.GlobalTransactional;
import jakarta.servlet.ServletException;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.connection.SortParameters;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.script.DefaultRedisScript;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.*;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

@Slf4j
@Service
@SuppressWarnings({"all"})
public class OrderInfoServiceImpl extends ServiceImpl<OrderInfoMapper, OrderInfo> implements OrderInfoService {

    @Autowired
    private OrderInfoMapper orderInfoMapper;

    @Autowired
    private RedisTemplate redisTemplate;

    @Autowired
    private UserFeignClient userFeignClient;

    @Autowired
    private AlbumFeignClient albumFeignClient;

    @Autowired
    private AccountFeignClient accountFeignClient;

    @Autowired
    private OrderDetailMapper orderDetailMapper;

    @Autowired
    private OrderDerateMapper orderDerateMapper;

    @Autowired
    private DelayMsgService delayMsgService;


    /**
     * 订单确认
     * @param tradeVo
     * @return
     */
    @Override
    public OrderInfoVo trade(TradeVo tradeVo) {
        OrderInfoVo orderInfoVo = new OrderInfoVo();
        Long userId = AuthContextHolder.getUserId();


        //金额信息
        BigDecimal OrderAmount = new BigDecimal("0.00");
        BigDecimal DerateAmount =new BigDecimal("0.00");
        BigDecimal OriginalAmount = new BigDecimal("0.00");


        //订单明细表
        List<OrderDerateVo> orderDerateVoList = new ArrayList<>();

        //订单减免表
        List<OrderDetailVo> orderDetailVoList =new ArrayList<>();




        if(SystemConstant.ORDER_ITEM_TYPE_ALBUM.equals(tradeVo.getItemType())){
            //如果是购买专辑
            /*
            * 要先查询用户是否购买了专辑
            * 用户不登陆显示付费标致 然后进行登陆购买专辑
            * */
            Boolean flag = userFeignClient.isPaidAlbum(tradeVo.getItemId()).getData();
            if(flag){
                throw  new GuiguException(400,"用户已购买专辑");
            }
            //获取用户vip情况
            UserInfoVo userInfoVo = userFeignClient.getUserInfoVo(userId).getData();
            Assert.notNull(userInfoVo,"获取用户基本信息失败");
            Integer isVip = userInfoVo.getIsVip();

            //判断专辑是否普通用户打折
            AlbumInfo albumInfo = albumFeignClient.getAlbumInfo(tradeVo.getItemId()).getData();
            BigDecimal discount = albumInfo.getDiscount();

            //原价
            OriginalAmount = albumInfo.getPrice();
            OrderAmount = OriginalAmount;
            //订单总金额 （普通用户的）
            if(discount.intValue() !=-1){
                OrderAmount = OriginalAmount.multiply(discount).divide(new BigDecimal(10),2, RoundingMode.HALF_UP);

            }

            //判断专辑是否vip用户打折
            if(isVip.intValue() !=-1){
                //用户是vip
                BigDecimal vipDiscount = albumInfo.getVipDiscount();
                if(vipDiscount.intValue() !=-1){
                    //专辑打折在计算
                    //vip的订单总金额
                    OrderAmount = OriginalAmount.multiply(discount).divide(new BigDecimal(10),2, RoundingMode.HALF_UP);
                }
            }
            //获取金额 折扣信息
            DerateAmount = OriginalAmount.subtract(OrderAmount);

            //订单明细表
            OrderDetailVo orderDetailVo = new OrderDetailVo();
            orderDetailVo.setItemId(albumInfo.getId());
            orderDetailVo.setItemUrl(albumInfo.getCoverUrl());
            orderDetailVo.setItemPrice(OriginalAmount);
            orderDetailVo.setItemName(albumInfo.getAlbumTitle());
            orderDetailVoList.add(orderDetailVo);
            //订单减免表
            OrderDerateVo orderDerateVo = new OrderDerateVo();
            orderDerateVo.setDerateType(SystemConstant.ORDER_DERATE_ALBUM_DISCOUNT);
            orderDerateVo.setDerateAmount(DerateAmount);
            orderDerateVo.setRemarks("专辑优惠："+DerateAmount);

        }else if(SystemConstant.ORDER_ITEM_TYPE_TRACK.equals(tradeVo.getItemType())){
            //购买的声音
            //获取需要购买的声音 （正常购买减去已经购买）
            List<TrackInfo> trackInfoList = albumFeignClient.getWaitBuyTrackInfoList(tradeVo.getItemId(), tradeVo.getTrackCount()).getData();
            Assert.notNull(trackInfoList,"获取用户需要购买的声音失败");

            //获取专辑信息
            AlbumInfo albumInfo = albumFeignClient.getAlbumInfo(trackInfoList.get(0).getAlbumId()).getData();
            Assert.notNull(albumInfo,"获取专辑信息失败");

            //原始金额 =付款总金额
            OriginalAmount = albumInfo.getPrice().multiply(new BigDecimal(trackInfoList.size()));
            OrderAmount =OriginalAmount;

            //遍历订单明细表--每个声音都要
            orderDetailVoList =   trackInfoList.stream().map(trackInfo -> {
                OrderDetailVo orderDetailVo = new OrderDetailVo();
                orderDetailVo.setItemId(trackInfo.getId());
                orderDetailVo.setItemName(trackInfo.getTrackTitle());
                orderDetailVo.setItemUrl(trackInfo.getCoverUrl());
                orderDetailVo.setItemPrice(albumInfo.getPrice());
                return orderDetailVo;
            }).collect(Collectors.toList());



        } else if(SystemConstant.ORDER_ITEM_TYPE_VIP.equals(tradeVo.getItemType())){
            //购买会员
            VipServiceConfig vipServiceConfig = userFeignClient.getVipServiceConfig(tradeVo.getItemId()).getData();
            Assert.notNull(vipServiceConfig,"VIP套餐不存在");
            //原始金额
             OriginalAmount = vipServiceConfig.getPrice();
             //付款总金额
            OrderAmount =vipServiceConfig.getDiscountPrice();
            //折扣价格
            DerateAmount =OriginalAmount.subtract(OrderAmount);
            //订单明细表
            //点单减免类型
            OrderDerateVo orderDerateVo = new OrderDerateVo();
            orderDerateVo.setDerateType(SystemConstant.ORDER_DERATE_VIP_SERVICE_DISCOUNT);
            orderDerateVo.setDerateAmount(DerateAmount);
            orderDerateVo.setRemarks("购买 VIP");
            orderDerateVoList.add(orderDerateVo);
            //订单减免表
            OrderDetailVo orderDetailVo = new OrderDetailVo();
            orderDetailVo.setItemId(tradeVo.getItemId());
            orderDetailVo.setItemName(vipServiceConfig.getName());
            orderDetailVo.setItemUrl(vipServiceConfig.getImageUrl());
            orderDetailVo.setItemPrice(OriginalAmount);
            orderDetailVoList.add(orderDetailVo);

        }

        //封装
        orderInfoVo.setOrderDerateVoList(orderDerateVoList);
        orderInfoVo.setOrderDetailVoList(orderDetailVoList);

        //金额
        orderInfoVo.setOrderAmount(OrderAmount);
        orderInfoVo.setDerateAmount(DerateAmount);
        orderInfoVo.setOriginalAmount(OriginalAmount);

        String orderNo =  IdUtil.fastSimpleUUID();
        orderInfoVo.setTradeNo(orderNo);
        orderInfoVo.setItemType(tradeVo.getItemType());
        //key
        String tradeNoKey = RedisConstant.ORDER_TRADE_NO_PREFIX + userId;
        //将key 流水好作为key value 存到redis中 防止订单重复提交 主键是唯一的 重复提交 会覆盖之前的流水号
        redisTemplate.opsForValue().set(tradeNoKey,orderNo,30, TimeUnit.MINUTES);

        //5.2 本次结算时间戳
        orderInfoVo.setTimestamp(DateUtil.current());
        //5.3 本次结算签名--防止数据篡改 --将整个orderInfoVo变成map中的value 在提交订单订单之前比较 查看是否会有变化 f12改变价格
        //5.3.1 将订单VO转为Map-将VO中支付方式null值去掉
        Map<String, Object> paramsMap = BeanUtil.beanToMap(orderInfoVo, false, true);
        //5.3.2 调用签名API对现有订单所有数据进行签名
        String sign = SignHelper.getSign(paramsMap);
        orderInfoVo.setSign(sign);

        return orderInfoVo;
    }

    /**
     * 提交订单
     * @param orderInfoVo
     * @param userId
     * @return
     */
    @Override
    @GlobalTransactional(rollbackFor = Exception.class)
    public Map<String, String> submitOrder(OrderInfoVo orderInfoVo, Long userId) {
    /*    OrderInfo orderInfo1 = new OrderInfo();
        orderInfo1.setUserId(2222L);
                   String orderNo = UuidUtils.generateUuid();
        orderInfo1.setOrderNo(orderNo);
        orderInfo1.setOrderStatus(SystemConstant.ORDER_STATUS_UNPAID);
        orderInfo1.setOrderAmount(orderInfoVo.getOrderAmount());
        orderInfo1.setDerateAmount(orderInfoVo.getDerateAmount());
        orderInfo1.setOriginalAmount(orderInfoVo.getOriginalAmount());
        orderInfo1.setItemType(orderInfoVo.getItemType());
        orderInfo1.setPayWay(SystemConstant.ORDER_PAY_ACCOUNT);
        orderInfoMapper.insert(orderInfo1);

*/
        Map<String, String> map = new HashMap<>();
        //1.判断订单的流水号
        String tradeNoKey = RedisConstant.ORDER_TRADE_NO_PREFIX + userId;
        //1.1 构建验证流水号lua脚本
        String scriptText = "if(redis.call('get', KEYS[1]) == ARGV[1]) then return redis.call('del', KEYS[1]) else return 0 end";

        //2.2 执行脚本，如果脚本返回结果为false 抛出异常即可
        DefaultRedisScript<Boolean> redisScript = new DefaultRedisScript<>(scriptText, Boolean.class);
        boolean flag = (boolean) redisTemplate.execute(redisScript, Arrays.asList(tradeNoKey), orderInfoVo.getTradeNo());
        if(!flag){
            throw  new GuiguException(400,"流水号异常");
        }

        //2.判断订单是否被串改
        //2.1 将提交订单VO参数转为Map 加签并未加入"payWay" ,手动将提交参数Map中payWay移除掉
        Map<String, Object> mapParams = BeanUtil.beanToMap(orderInfoVo);
        mapParams.remove("payWay");
        mapParams.remove("DerateAmount");
        //2.2 调用签名工具类进行验签
        SignHelper.checkSign(mapParams);



        //3.新增一个订单信息表
        OrderInfo orderInfo =this.saveOrderInfo(orderInfoVo,userId);

        //4.修改用户的账户的金额（扣钱）
        if(orderInfoVo.getPayWay().equals(SystemConstant.ORDER_PAY_ACCOUNT)) {
            //余额支付
            AccountLockVo accountDeductVo = new AccountLockVo();
            accountDeductVo.setUserId(userId);
            accountDeductVo.setOrderNo(orderInfo.getOrderNo());
            accountDeductVo.setAmount(orderInfo.getOrderAmount());
            accountDeductVo.setContent(orderInfo.getOrderTitle());
            //远程修改用户账单
            Result result = accountFeignClient.checkAndDeduct(accountDeductVo);
            if (result.getCode() != 200) {
                throw new GuiguException(400, "用户金额扣费失败");
            }


            //新增用户付款记录（专辑 vip 声音）
            /**
             * userid orderno albumId trackId itemType
             */
            UserPaidRecordVo userPaidRecordVo = new UserPaidRecordVo();
            userPaidRecordVo.setOrderNo(orderInfo.getOrderNo());
            userPaidRecordVo.setUserId(userId);
            userPaidRecordVo.setItemType(orderInfoVo.getItemType());
            List<Long> itemList = orderInfoVo.getOrderDetailVoList().stream().map(orderDetailVo -> orderDetailVo.getItemId()).collect(Collectors.toList());
            userPaidRecordVo.setItemIdList(itemList);
            //远程调用修改用户的付款记录
            Result result1 = userFeignClient.savePaidRecord(userPaidRecordVo);
            if (result1.getCode() != 200) {
                throw new GuiguException(400, "用户新增付款记录失败");
            }

            //修改订单支付状态
            orderInfo.setOrderStatus(SystemConstant.ORDER_STATUS_PAID);
            orderInfoMapper.updateById(orderInfo);
        }

        //发送延迟消息--完成订单延迟关闭
        if(orderInfoVo.getPayWay().equals(SystemConstant.ORDER_PAY_WAY_WEIXIN)){
            //微信支付的话 发送延迟消息
            delayMsgService.sendDelayMessage(RedisConstant.CACHE_INFO_PREFIX,orderInfo.getId().toString(), 30);
        }

        //响应前端数据
        map.put("orderNo",orderInfo.getOrderNo());
        return map;
    }

    //新增用户订单表
    @Transactional(rollbackFor = Exception.class)
    private OrderInfo saveOrderInfo(OrderInfoVo orderInfoVo, Long userId) {
        OrderInfo orderInfo = new OrderInfo();
        //订单基本信息
        orderInfo.setUserId(userId);
        String orderNo = IdUtil.fastSimpleUUID();
        orderInfo.setOrderNo(orderNo);
        orderInfo.setOrderStatus(SystemConstant.ORDER_STATUS_UNPAID);
        orderInfo.setOrderAmount(orderInfoVo.getOrderAmount());
        orderInfo.setDerateAmount(orderInfoVo.getDerateAmount());
        orderInfo.setOriginalAmount(orderInfoVo.getOriginalAmount());
        orderInfo.setItemType(orderInfoVo.getItemType());
        orderInfo.setOrderTitle("fjddfdkfkjdkjfbdjk订单名字");
        orderInfo.setPayWay(SystemConstant.ORDER_PAY_ACCOUNT);

        //先报存到数据库 返回订单id
        orderInfoMapper.insert(orderInfo);

        //订单减免表
        List<OrderDerateVo> orderDerateVoList = orderInfoVo.getOrderDerateVoList();
        List<OrderDerate> orderDerateList = orderDerateVoList.stream().map(orderDerateVo -> {
            OrderDerate orderDerate = new OrderDerate();
            BeanUtil.copyProperties(orderDerateVo,orderDerate);
            //少一个订单id
            orderDerate.setOrderId(orderInfo.getId());
            orderDerateMapper.insert(orderDerate);
            return orderDerate;
        }).collect(Collectors.toList());


        //订单明细表
        List<OrderDetailVo> orderDetailVoList = orderInfoVo.getOrderDetailVoList();
        List<OrderDetail> orderDetailList = orderDetailVoList.stream().map(orderDetailVo -> {
            OrderDetail orderDetail = new OrderDetail();
            BeanUtil.copyProperties(orderDetailVo,orderDetail);
            //少一个订单id
            orderDetail.setOrderId(orderInfo.getId());
            orderDetailMapper.insert(orderDetail);
            return orderDetail;
        }).collect(Collectors.toList());

        orderInfo.setOrderDerateList(orderDerateList);
        orderInfo.setOrderDetailList(orderDetailList);

        return orderInfo;
    }


    /**
     * 查询当前用户指定订单信息
     * @param orderNo
     * @param userId
     * @return
     */
    @Override
    public OrderInfo getOrderInfo(String orderNo) {
        Long userId = AuthContextHolder.getUserId();
        OrderInfo orderInfo = orderInfoMapper.selectOne(new LambdaQueryWrapper<OrderInfo>()
                .eq(OrderInfo::getOrderNo, orderNo)
                .eq(OrderInfo::getUserId, userId));
        if(orderInfo!=null){
            //订单明细表
            List<OrderDetail> orderDetailList = orderDetailMapper.selectList(new LambdaQueryWrapper<OrderDetail>().eq(OrderDetail::getOrderId, orderInfo.getId()));
            orderInfo.setOrderDetailList(orderDetailList);

            //设置中文的未支付 支付 余额 支付宝   微信
            orderInfo.setOrderStatusName(this.getOrderStatusName(orderInfo.getOrderStatus()));
            orderInfo.setPayWayName(this.getPayWayName(orderInfo.getPayWay()));
            return orderInfo;
        }
        return null;
    }


    /**
     * 分页获取当前用户订单列表
     * @param orderInfoPage
     * @param userId
     * @return
     */
    @Override
    public Page<OrderInfo> findUserPage(Page<OrderInfo> orderInfoPage, Long userId) {
        Page<OrderInfo>  orderInfo=  orderInfoMapper.findUserPage(orderInfoPage,userId);
        if(orderInfo!=null){
            List<OrderInfo> records = orderInfo.getRecords();
            for (OrderInfo info : records) {
                info.setOrderStatusName(this.getOrderStatusName(info.getOrderStatus()));
                info.setPayWayName(this.getPayWayName(info.getPayWay()));
            }

            return orderInfo;
        }
        return null;
    }

    /**
     * 超时取消订单
     * @param valueOf
     */
    @Override
    public void orderCanncal(Long valueOf) {
        OrderInfo orderInfo = orderInfoMapper.selectOne(new LambdaQueryWrapper<OrderInfo>().eq(OrderInfo::getId, valueOf));
        if(orderInfo!=null && SystemConstant.ORDER_STATUS_UNPAID.equals(orderInfo.getOrderStatus())){
            //订单不为空 且订单状态未未支付
            orderInfo.setOrderStatus(SystemConstant.ORDER_STATUS_CANCEL);
            orderInfoMapper.insert(orderInfo);
        }

    }

    private String getOrderStatusName(String orderStatus) {
        if (SystemConstant.ORDER_STATUS_UNPAID.equals(orderStatus)) {
            return "未支付";
        } else if (SystemConstant.ORDER_STATUS_PAID.equals(orderStatus)) {
            return "已支付";
        } else if (SystemConstant.ORDER_STATUS_CANCEL.equals(orderStatus)) {
            return "取消";
        }
        return null;
    }

    /**
     * 根据支付方式编号得到支付名称
     *
     * @param payWay
     * @return
     */
    private String getPayWayName(String payWay) {
        if (SystemConstant.ORDER_PAY_WAY_WEIXIN.equals(payWay)) {
            return "微信";
        } else if (SystemConstant.ORDER_PAY_ACCOUNT.equals(payWay)) {
            return "余额";
        } else if (SystemConstant.ORDER_PAY_WAY_ALIPAY.equals(payWay)) {
            return "支付宝";
        }
        return "";
    }


    /**
     * 用户支付成功后，修改订单状态(远程调用用户服务-新增用户购买记录)
     *
     * @param orderNo 订单编号
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void orderPaySuccess(String orderNo) {
        //修改订单状态
        OrderInfo orderInfo = this.getOrderInfo(orderNo);
        if(orderInfo != null && SystemConstant.PAYMENT_STATUS_PAID.equals(orderInfo.getOrderStatus())){
            //修改完成
            return;
        }
        //更改状态
        orderInfo.setOrderStatus(SystemConstant.PAYMENT_STATUS_PAID);
        orderInfoMapper.insert(orderInfo);

        //更新用户购买记录
        UserPaidRecordVo userPaidRecordVo = new UserPaidRecordVo();
        userPaidRecordVo.setOrderNo(orderInfo.getOrderNo());
        userPaidRecordVo.setUserId(orderInfo.getUserId());
        userPaidRecordVo.setItemType(orderInfo.getItemType());
        //遍历订单中订单商品明细封装购买项目ID
        //如果是专辑或者vip只购买一个 但是考虑到之前的声音 所以用的集合来装的
        List<Long> longs = orderInfo.getOrderDetailList().stream().map(orderDetail -> {
            return orderDetail.getItemId();
        }).collect(Collectors.toList());
        userPaidRecordVo.setItemIdList(longs);

        Result userResult = userFeignClient.savePaidRecord(userPaidRecordVo);
        if(200!= userResult.getCode()){
            throw new GuiguException(500, "新增购买记录异常！");
        }
    }
}
